package egs.client;

import java.io.IOException;

import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.Security;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import egs.comms.ClientConnection;
import egs.comms.EGSCommunicationException;
import egs.games.CheckersClient;
import egs.games.CheckersGame;
import egs.games.Game;
import egs.games.GameException;
import egs.games.TicTacToeGame;
import egs.games.TicTacToeGameException;
import egs.packets.AuthLoginPacket;
import egs.packets.BoardSendPacket;
import egs.packets.DisconnectPacket;
import egs.packets.EndGamePacket;
import egs.packets.GameListPacket;
import egs.packets.InvalidGamePacket;
import egs.packets.InvalidPacketException;
import egs.packets.MoveResponsePacket;
import egs.packets.MoveSendPacket;
import egs.packets.OppAckPacket;
import egs.packets.OppChoicePacket;
import egs.packets.OppListPacket;
import egs.packets.OppNackPacket;
import egs.packets.OppOfferPacket;
import egs.packets.Packet;
import egs.packets.PacketException;
import egs.packets.SelectGamePacket;
import egs.packets.UseSecurePacket;
import egs.packets.UseSecureResponsePacket;
import egs.packets.DisconnectPacket.ReasonCode;
import egs.packets.UseSecurePacket.SecurityCode;
import egs.packets.UseSecureResponsePacket.ResponseCode;
import egs.server.ClientState;
import egs.server.ClientThread;

public class EGSClient 
{
	public static final int EGS_PORT = 13337;
    public static final int EGS_TLS_PORT = 13338;
    
    public static final short[][] game_list = new short[][] { {Packet.GAME_NAME_CHECKERS, 1}, {Packet.GAME_NAME_TICTACTOE, 1} };
    
    private static InetAddress serverAddy = null;
    private static boolean useSecure = false;
	private static int connectionPort;
	private static int state = ClientState.CONTROL;
	private static Packet pkt;
	private static ClientConnection connection = null;
	private static Socket socket;
	private static short gameName = 0;
	private static CheckersClient checkersClient = null;
	private static TicTacToeGame tictactoeGame = null; 
	private static short[][] serverGameList = null;
	private static List<String> oppList;
	private static short gameVersion;
	private static boolean oppChoiceAckd = false;
	private static String replayMoveFilePath = null;
	private static int replayDelay = -1;
	
    public static void main( String argv[] ) 
    {
    	if(!parseArgs(argv))
    	{
    		printHelp();
    		return;
    	}

    	try {
    		initClientLogs();
    	} catch(IOException ex){
    		ex.printStackTrace();
    		return;
    	}
    	
    	initialConnect(useSecure);
		
    	while(socket.isBound())
    	{
    		try
    		{
	    		pkt = connection.getPacket();
				handlePacket(pkt);
	    	} catch (InvalidPacketException pe) {
				System.err.println("Invalid message: " + pe );
				// do something more to handle it. Close the connection?
				connection.closeConnection();
				return;
			} catch (EGSCommunicationException e) {
				System.err.println("Error sending data: " + e );
	            // do something more to handle it. Close the connection? 
				connection.closeConnection();
	            return;
			}
    	}
    }

    private static void initClientLogs() throws IOException 
    {
    	CheckersClient.initLogs();		
	}

	private static void initialConnect(boolean connectSecure)
    {
    	SecurityCode securityCode;
    	if (connectSecure)
    		securityCode = SecurityCode.tls;
    	else
    		securityCode = SecurityCode.none;
		connectionPort = EGS_PORT;
    	
    	socket = null;
		try {
			socket = new Socket(serverAddy, connectionPort);
			connection = new ClientConnection(socket);
		} catch (IOException e) {
			System.err.println("Error starting game client: could not send on port: " + connectionPort);
			return;
		}
		
		UseSecurePacket useSecurePacket = new UseSecurePacket(securityCode);
		try{
			connection.sendPacket(useSecurePacket);
		} catch (EGSCommunicationException ex) {
			System.err.println("Error sending data: " + ex );
            // do something more to handle it. Close the connection? 
			connection.closeConnection();
            return;
		}
		
	}

	private static void handlePacket(Packet pkt) throws EGSCommunicationException {
		switch (state) {
		case ClientState.CONTROL:
			handlePacketForControl(pkt);
			break;
		case ClientState.UNAUTHENTICATED:
			handlePacketForUnauthenticated(pkt);
			break;
		case ClientState.AUTHENTICATED:
			handlePacketForAuthenticated(pkt);
			break;
		case ClientState.GAME_SELECTED:
			handlePacketForGameSelected(pkt);
			break;
		case ClientState.OPPONENT_WAIT:
			handlePacketForOpponentWait(pkt);
			break;
		case ClientState.IN_GAME:
			handlePacketForInGame(pkt);
			break;
		case ClientState.MAKE_MOVE:
			handlePacketForMakeMove(pkt);
			break;
		}
	}

	private static void handlePacketForMakeMove(Packet pkt) throws EGSCommunicationException 
	{
		if (pkt.get_message_type() == Packet.MSG_MOVE_RESPONSE)
		{
			MoveResponsePacket moveResponse = (MoveResponsePacket)pkt;
			if(moveResponse.get_response_code() != 0)
			{
				try {
					doGameMove();
				} catch (Exception ex) {
					System.err.println("Error: " + ex);
					logout(ReasonCode.client_error);
					state = ClientState.CONTROL;
				}
			}
			else
			{
				updateClientDisplay();
				System.out.println("Waiting for opponent ...");
				state = ClientState.IN_GAME;
			}
		}
		else
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in MAKE_MOVE state.");
		}
	}

	private static void handlePacketForInGame(Packet pkt) throws EGSCommunicationException 
	{
		if (pkt.get_message_type() == Packet.MSG_BOARD_SEND)
		{
			state = ClientState.MAKE_MOVE;
			BoardSendPacket boardSend = (BoardSendPacket)pkt;
			int[][] board = boardSend.get_board();
			int playerNum = boardSend.get_player_number();
			
			if (!receiveMove(board, playerNum))
			{
				logout(ReasonCode.opp_error);
				state = ClientState.CONTROL;
				return;
			}
		}
		else if (pkt.get_message_type() == Packet.MSG_END_GAME)
		{
			EndGamePacket endGame = (EndGamePacket)pkt;
			doEndGame(endGame.get_reason_code());
			clearClient();
			state = ClientState.AUTHENTICATED;
			
			if (serverGameList != null && serverGameList.length > 0) {
				boolean gameSelected = selectGame();
				if (!gameSelected)
				{
					logout(ReasonCode.client_quit);
					state = ClientState.CONTROL;
					return;
				}
			} else {
				logout(ReasonCode.client_error);
				state = ClientState.CONTROL;
				return;
			}
		}
		else
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in IN_GAME state.");
		}
	}

	private static void handlePacketForOpponentWait(Packet pkt) throws EGSCommunicationException 
	{
		if (pkt.get_message_type() == Packet.MSG_OPP_NACK)
		{
			state = ClientState.GAME_SELECTED;
			System.out.println("Opponent rejected offer.");
			boolean oppSelected = makeOppChoice();
			if (!oppSelected)
			{
				logout(ReasonCode.client_quit);
				state = ClientState.CONTROL;
				return;
			}
			state = ClientState.OPPONENT_WAIT;
		}
		else if(pkt.get_message_type() == Packet.MSG_OPP_OFFER)
		{
			OppOfferPacket oppOffer = (OppOfferPacket)pkt;
			boolean offerAccepted = receiveOppOffer(oppOffer.get_user_name());
			if (offerAccepted)
			{
				OppAckPacket responsePacket = null;
				try{
					responsePacket = new OppAckPacket(gameName, gameVersion, oppOffer.get_user_name());
				} catch (PacketException ex) {
					System.out.println("Unexpected error sending opponent ack: " + ex.getMessage());
					logout(ReasonCode.client_error);
					state = ClientState.CONTROL;
					return;
				}
				connection.sendPacket(responsePacket);
				state = ClientState.IN_GAME;
			}
			else
			{
				OppNackPacket responsePacket = new OppNackPacket(OppNackPacket.ReasonCode.opp_reject);
				connection.sendPacket(responsePacket);
			}
		}
		else if(pkt.get_message_type() == Packet.MSG_OPP_ACK)
		{		
			OppAckPacket oppAck = (OppAckPacket)pkt;			
				
			doAckOpp(oppAck.get_user_name());
			state = ClientState.IN_GAME;
		}
		else 
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in OPPONENT_WAIT state.");
		}
		
	}

	private static void handlePacketForGameSelected(Packet pkt) throws EGSCommunicationException 
	{
		System.err.println(
				"Unexpected packet message type " + 
				pkt.get_message_type() + 
				" received in GAME_SELECTED state.");		
	}

	private static void handlePacketForAuthenticated(Packet pkt) throws EGSCommunicationException 
	{
		if (pkt.get_message_type() == Packet.MSG_OPP_LIST)
		{
			state = ClientState.GAME_SELECTED;
			
			OppListPacket oppListPkt = (OppListPacket) pkt;
			gameName = oppListPkt.get_game_name();
			gameVersion = oppListPkt.get_game_version();
			oppList = oppListPkt.get_opp_list();
			
			boolean oppSelected = makeOppChoice();
			if (!oppSelected)
			{
				logout(ReasonCode.client_quit);
				state = ClientState.CONTROL;
				return;
			}
			state = ClientState.OPPONENT_WAIT;
		}
		else if(pkt.get_message_type() == Packet.MSG_INVALID_GAME)
		{
			InvalidGamePacket invalidGamePkt = (InvalidGamePacket) pkt;
			System.out.println("Server responded with invalid game: " + getGameName(invalidGamePkt.get_packet_game_name()) + 
					" , version: " + invalidGamePkt.get_packet_game_version());
			boolean gameSelected = selectGame();
			if (!gameSelected)
			{
				logout(ReasonCode.client_quit);
				state = ClientState.CONTROL;
				return;
			}
		}
		else
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in AUTHENTICATED state.");
		}
		
	}

	private static void handlePacketForUnauthenticated(Packet pkt) throws EGSCommunicationException 
	{
		if(pkt.get_message_type() == Packet.MSG_GAME_LIST) 
		{
			state = ClientState.AUTHENTICATED;
			
			GameListPacket gameListPkt = (GameListPacket) pkt;
			serverGameList = gameListPkt.get_game_list();
			if (serverGameList == null || serverGameList.length == 0)
			{
				System.out.println("Server responded:  no games supported.");
				logout(ReasonCode.client_quit);
				state = ClientState.CONTROL;
				return;
			}
			
			boolean gameSelected = selectGame();
			if (!gameSelected)
			{
				logout(ReasonCode.client_quit);
				state = ClientState.CONTROL;
				return;
			}
		}
		else if (pkt.get_message_type() == Packet.MSG_AUTH_LOGIN_ERR)
		{
			System.out.println("Server responded with: Invalid login.");
			authenticate();
		}
		else
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in UNAUTHENTICATED state.");
		}
		
	}

	private static void handlePacketForControl(Packet pkt) 
	{
		if (pkt.get_message_type() == Packet.MSG_USE_SECURE_RESPONSE)
		{
			UseSecureResponsePacket response = (UseSecureResponsePacket) pkt;
			ResponseCode code = response.get_response_code();
			if (code == ResponseCode.accepted)
			{
				if (useSecure)
				{
					int securePort = response.getPort();
					try	{
						socket = connection.secureConnect(serverAddy.getHostName(), securePort);
					} catch (IOException ex) {
						System.err.println("Error establishing secure connection: could not send on port: " + securePort);
						return;
					}					
				}
				state = ClientState.UNAUTHENTICATED;
				authenticate();
			}
			else if (code == ResponseCode.unsupported_protocol)
			{
				useSecure = false;
				initialConnect(false);
			}
			else if (code == ResponseCode.connection_error)
			{
				// TODO: WTF to do here?
				System.err.println("Connection error encountered.");
				connection.closeConnection();
			}
		}
		else
		{
			System.err.println(
					"Unexpected packet message type " + 
					pkt.get_message_type() + 
					" received in CONTROL state.");
		}
	}

	private static boolean authenticate() 
	{
		try
		{
			String username = ClientInput.getClientInputObject().promptUserString("username:");
			String password = ClientInput.getClientInputObject().promptUserString("password:");
			
			boolean authSent = false;
			while(!authSent)
			{
				try
				{
					AuthLoginPacket authLogin = new AuthLoginPacket(username, password, game_list);
					connection.sendPacket(authLogin);
					authSent = true;
				}catch (PacketException e) {
					System.err.println("Error authenticating: " + e);
				}
			}
		}
		catch (IOException e) {
			System.err.println("Error authenticating: " + e);
			return false;
		}
		
		return true;
	}

	private static boolean receiveMove(int[][] board, int playerNum) 
	{
		try
		{
			switch(gameName){
			case Packet.GAME_NAME_CHECKERS:
				return receiveCheckersMove(board, playerNum);
			case Packet.GAME_NAME_TICTACTOE:
				return receiveTicTacToeMove(board, playerNum);
			}
		}
		catch (Exception ex) {
			System.out.println("Error while receiving opponent move: " + ex.getMessage());
			return false;
		}
		
		return false;
		
	}

	private static boolean receiveCheckersMove(int[][] board, int egsPlayerNum) 
	{
		int checkersPlayerNum = egsPlayerNum;
		int result = CheckersGame.VALID;
		if (checkersClient == null)
		{
			checkersClient = new CheckersClient(new CheckersGame(board), checkersPlayerNum);
			if (replayMoveFilePath != null)
			{
				try {
					checkersClient.queueReplayMoves(replayMoveFilePath, replayDelay);
				} catch(IOException ex) {
					System.err.println("Error reading replay move file: " + replayMoveFilePath);
				}
			}
				
		}
		else
		{
			result = checkersClient.getGame().updateState(board);
		}
		
		updateClientDisplay();
		
		if (result == CheckersGame.VALID)
		{
			try {
				return doGameMove();
			} catch (Exception ex){
				System.err.println("Error: " + ex);
				return false;
			}
		}
		else
		{
			System.out.println("Opponent move invalid.  Move error code: " + result);
			return false;
		}
	}

	private static boolean receiveTicTacToeMove(int[][] board, int playerNum) throws TicTacToeGameException 
	{
		int result = Game.VALID;
		if (tictactoeGame == null)
			tictactoeGame = new TicTacToeGame(board, playerNum);
		else
			result = tictactoeGame.updateState(board);
		
		updateClientDisplay();
		
		if (result == Game.VALID)
		{
			try {
				return doGameMove();
			} catch (Exception ex){
				System.err.println("Error: " + ex);
				return false;
			}
		}
		else
		{
			System.out.println("Opponent move invalid.  Move error code: " + result);
			return false;
		}
	}
	
	private static boolean doGameMove() throws IOException, InterruptedException
	{
		boolean validMove = false;
		while(!validMove)
		{
			if (gameName == Packet.GAME_NAME_CHECKERS)
			{	
				String move = checkersClient.getMove();
				if(move.equalsIgnoreCase("exit") || move.equalsIgnoreCase("quit"))
					return false;
				validMove = checkersClient.executeMove(move);
				if (validMove)
				{
					MoveSendPacket moveSend = new MoveSendPacket(Packet.GAME_NAME_CHECKERS, 
							checkersClient.getGame().getGameVersion(), 
							checkersClient.getGame().getBoardState());
					connection.sendPacket(moveSend);
				}
			}
			else if (gameName == Packet.GAME_NAME_TICTACTOE)
			{
				String move = tictactoeGame.getMove();
				validMove = tictactoeGame.executeMove(move);
				if (validMove)
				{
					MoveSendPacket moveSend = new MoveSendPacket(Packet.GAME_NAME_TICTACTOE, 
							tictactoeGame.getGameVersion(), 
							tictactoeGame.getRawBoard());
					connection.sendPacket(moveSend);
				}
			}
		}
		
		return true;
	}

	private static void doAckOpp(String oppUsername) throws EGSCommunicationException 
	{
		/*
		// Adding to DFA in order to make server-side coding easier
		try {
			 connection.sendPacket(new OppAckPacket(gameName, gameVersion, oppUsername));
		} catch (PacketException ex) { 
			System.out.println("Error: " + ex.getMessage());
		}
		*/
		
		System.out.println("Opponent accepted game offer: " + oppUsername.trim());
		System.out.println("Waiting for starting board ...");
	}

	private static void clearClient() 
	{
		checkersClient = null;
		tictactoeGame = null;
		
		gameName = 0;
	}

	private static void doEndGame(EndGamePacket.ReasonCode endGameState) 
	{
		switch (endGameState){
		case loss :
			System.out.println("You lost.");
			break;
		case win :
			System.out.println("You won!");
			break;
		case tie :
			System.out.println("Tie game.");
			break;
		case opp_timeout :
			System.out.println("Opponent timed out.");
			break;
		case timeout :
			System.out.println("You have timed out.");
			break;
		case server_error :
			System.out.println("Server Error.");
			break;
		}
	}
	
	private static boolean selectGame() throws EGSCommunicationException  
	{
		System.out.println("Games available on server:");
		ArrayList<Integer> invalidGames = new ArrayList<Integer>();
		
		for (int i = 0; i < serverGameList.length; i++)
		{
			short gameOption = serverGameList[i][0];
			short gameVersion = serverGameList[i][1];
			
			boolean versionMatches = checkGameVersion(gameOption, gameVersion);
			String gameChoiceName = getGameName(gameOption);
			if (versionMatches)
				System.out.println(i + " -\t\t" + gameChoiceName);
			else
			{
				invalidGames.add(i);
				if (gameChoiceName == null)
					System.out.println(i + " -\t\t" + "INVALID. VERSION MISMATCH.");
				else
					System.out.println(i + " -\t\t" + gameChoiceName + " - INVALID. VERSION MISMATCH.");
			}	
		}
		
		int selection = -2;
		while (selection == -2)
		{
			try {
				selection = ClientInput.getClientInputObject().promptUserInt(
						"Please select your game (-1 to exit): ");
				if (invalidGames.contains(selection))
					System.out.println("Selection invalid, game versions do not match.  Server version: " + serverGameList[selection][1] + 
							".  Client version: " + getClientVersion(serverGameList[selection][0]));
				else if(selection < -1 || selection >= serverGameList.length)
					System.out.println("Invalid entry.");
				
			} catch(NumberFormatException ex) {
				System.out.println("Invalid entry.");
			} catch(IOException ex) {
				System.out.println("Unexpected error selecting game.");
				return false;
			}
		}
		
		if (selection == -1)
			return false;
		
		SelectGamePacket selectGame = new SelectGamePacket((short)0, serverGameList[selection][0], 
				serverGameList[selection][1]);
		
		connection.sendPacket(selectGame);
		
		return true;
	}
	
	private static boolean makeOppChoice() throws EGSCommunicationException 
	{
		System.out.println("Opponents available: ");
		for (int i = 0; i < oppList.size(); i++)
		{
			String opp = oppList.get(i);
			System.out.println((i+1) + " -\t\t" + opp.trim());
		}
		
		OppChoicePacket oppChoicePkt = null;
		while (oppChoicePkt == null)
		{
			int selectedOpponent = -2;
			try
			{
				selectedOpponent = ClientInput.getClientInputObject().promptUserInt(
					"Please select opponent (0 to wait, -1 to exit): ");
			} catch(IOException ex) {
				System.out.println("Unexpected error while getting opponent choice.");
				return false;
			}
			
			if (selectedOpponent == -1)
				return false;
			else if (selectedOpponent == 0)
			{
				try {
					 oppChoicePkt = new OppChoicePacket(gameName, gameVersion, true, "");
				} catch (PacketException ex) { 
					System.out.println("Error: " + ex.getMessage());
				}
			}
			else if (selectedOpponent > 0 && selectedOpponent <= oppList.size())
			{
				try {
					 oppChoicePkt = new OppChoicePacket(gameName, gameVersion, false, oppList.get(selectedOpponent -1).trim());
				} catch (PacketException ex) { 
					System.out.println("Error: " + ex.getMessage());
				}
				
			}
			else
				System.out.println("Invalid opponent choice.");
		}
		
		if (oppChoicePkt != null)
		{
			connection.sendPacket(oppChoicePkt);
			return true;
		}
		else
			return false;
		
	}
	
	private static boolean receiveOppOffer(String oppName) throws EGSCommunicationException 
	{
		System.out.println("Opponent " + oppName.trim() + " would like to play you.");
		
		int choice = -1;
		while (choice != 0 && choice != 1)
		{
			try
			{
				choice = ClientInput.getClientInputObject().promptUserInt("Will you accept? Enter 0 for no, 1 for yes: ");
			} catch(NumberFormatException ex) {
				System.out.println("Invalid choice.");
			} catch(IOException ex ){
				System.out.println("Error reading choice.");
			}
			
			if (choice != 0 && choice != 1)
				System.out.println("Invalid choice.");
		}
		
		return choice == 1;
	}

	private static String getGameName(short game2) 
	{
		switch (game2){
		case Packet.GAME_NAME_CHECKERS:
			return "Checkers";
		case Packet.GAME_NAME_TICTACTOE:
			return "Tic-Tac-Toe";
		}
		
		return null;
	}

	private static boolean checkGameVersion(short game2, short gameVersion) 
	{
		return getClientVersion(game2) == gameVersion;
	}

	private static short getClientVersion(short game2) 
	{
		switch (game2) {
		case Packet.GAME_NAME_CHECKERS:
			return new CheckersGame(new int[][] {{1, 0} ,{0, 3}}).getGameVersion();
		case Packet.GAME_NAME_TICTACTOE:
			return new TicTacToeGame().getGameVersion();
		}
		
		return -1;
	}
	
	private static void updateClientDisplay()
	{
		switch(gameName){
		case Packet.GAME_NAME_CHECKERS:
			checkersClient.updateBoardDisplay();
			break;
		case Packet.GAME_NAME_TICTACTOE:
			tictactoeGame.updateBoardDisplay();
			break;
		}
		
	}
	
	private static void logout(DisconnectPacket.ReasonCode reason) throws EGSCommunicationException 
	{
		System.out.println("Exiting session.  Reason:" + getErrorReason(reason));
		
		DisconnectPacket pkt = new DisconnectPacket(reason);
		
		clearSessionState();
		connection.sendPacket(pkt);
	}
	
	private static void clearSessionState()
	{
		clearClient();
		gameName = 0;
		gameVersion = 0;
		serverGameList = null;
		oppList = null;
	}

	private static String getErrorReason(DisconnectPacket.ReasonCode reason) 
	{
		switch(reason){
		case client_error :
			return "client error";
		case client_quit :
			return "client quit";
		case opp_error : 
			return "opponent error";
		case opp_left : 
			return "opponent quit";
		case opp_timeout :
			return "opponent timed out";
		}
		
		return "unknown error";
	}

	private static void printHelp() {
        System.out.println( "EGS Game Client Usage:" );
        System.out.println( "  Required Args:" );
        System.out.println( "    -s <TLS|None>" );
        System.out.println( "    -n <server_name>" );
        System.out.println( "  Optional Args:" );
        System.out.println( "    -r <replay_move_file> <replay_delay_in_ms>");
	}

	private static boolean parseArgs(String[] argv) {
        boolean sec_found = false;
        boolean addr_found = false;

        for ( int i = 0; i < argv.length; i++ ) {

            if ( argv[i].equals( "-s" ) ) {
                if ( i+1 == argv.length ) {
                    System.err.println( "Ran out of arguments parsing -s" );
                    return false;
                }
                if ( sec_found ) {
                    System.err.println( "Invalid multiple use of -s" );
                    return false;
                }

                if ( argv[i+1].equals("TLS") ) {
                    useSecure = true; sec_found = true;
                } else if ( argv[i+1].equals("None") ) {
                    useSecure = false; sec_found = true;
                } else {
                    System.err.println( "Invalid security model:" + argv[i+1] );
                    return false;
                }
                System.out.println( "Using security model: " + argv[i+1] );

                i++;

            } else if ( argv[i].equals( "-n" ) ) {
                if ( i+1 == argv.length ) {
                    System.err.println( "Ran out of arguments parsing -n" );
                    return false;
                }
                if ( addr_found ) {
                    System.err.println( "Invalid multiple use of -n" );
                    return false;
                }

                System.out.println( "Looking up IP for server: " + argv[i+1] );
                try {
                    serverAddy = InetAddress.getByName( argv[i+1] );
                } catch ( UnknownHostException uhe ) {
                    System.err.println( "Failed to get IP for hostname: " + argv[i+1] );
                    return false;
                }

                System.out.println( "Lookup successed as: " + serverAddy );

                addr_found = true;
                i++;

            } 
            else if ( argv[i].equals( "-r" ) ) {
                if ( i+2 == argv.length ) {
                    System.err.println( "Ran out of arguments parsing -r" );
                    return false;
                }
                
                replayMoveFilePath = argv[i+1];
                try {
                	replayDelay  = Integer.parseInt(argv[i+2]);
                } catch(NumberFormatException ex) {
                	System.err.println("Failed to parse replay delay as integer.");
                	return false;
                }
                
                i = i+2;
            }
            else {
                System.err.println( "Unknown argument: " + argv[i] );
            }
        }
        
		return (sec_found && addr_found);
	}
}
